package com.zhang.redis.util;

import com.zhang.redis.config.MyRedissonConfig;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * 深圳金雅福控股集团有限公司
 *
 * @author zhangfanjun
 * @date 2021/11/17
 */
@Slf4j
@Component
@AutoConfigureAfter(MyRedissonConfig.class)
public class RedissonManager {

    @Resource(name = "stringRedisson")
    private RedissonClient stringRedisson;

    @Resource(name = "jsonRedisson")
    private RedissonClient jsonRedisson;


    /**
     * @param key  锁
     * @param time 失效时间
     * @param fun  函数
     * @return 解锁的时间采用秒，不推荐直接使用本方法
     * @author zfj
     * @date 2022/4/5
     */
    public void lock(String key, long time, EmtyInFunction fun) throws Throwable {
        RLock lock = stringRedisson.getLock(key);
        try {
            lock.lock(time, TimeUnit.SECONDS);
            fun.doAction();
        } finally {
            lock.unlock();
        }
    }

    /**
     * @param key  锁
     * @param time 失效时间
     * @param fun  函数
     * @return 尝试锁
     * @author zfj
     * @date 2022/4/5
     */
    public void tryLock(String key, long time, EmtyInFunction fun) throws Throwable {
        tryLock(key,time,time,fun);
    }

    /**
     * @param key  锁
     * @param waitTime 等待时间
     * @param leaseTime 释放时间
     * @param fun  函数
     * @return 尝试锁
     * @author zfj
     * @date 2022/4/5
     */
    public void tryLock(String key, long waitTime, long leaseTime, EmtyInFunction fun) throws Throwable {
        RLock lock = stringRedisson.getLock(key);
        try {
            if (lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS)) {
                log.info("获取锁：key：{}", key);
                try {
                    fun.doAction();
                } catch (Throwable e) {
                    log.error("业务发生异常：", e);
                    throw e;
                }
            }
        } catch (Exception e) {
            log.error("发生异常：", e);
            throw e;
        } finally {
            lock.unlock();
            log.info("释放锁：key：{}", key);
        }
    }

    public Object tryLockhasResult(String key, long time, ResultFunction fun) throws Exception {
        RLock lock = stringRedisson.getLock(key);
        Object result = null;
        try {
            if (lock.tryLock(time, time, TimeUnit.SECONDS)) {
                log.info("获取锁：key：{}", key);
                try {
                    result = fun.doAction();
                } catch (Exception e) {
                    log.error("业务发生异常：", e);
                    throw e;
                }
            }
        } catch (Exception e) {
            log.error("发生异常：", e);
            throw e;
        } finally {
            lock.unlock();
            log.info("释放锁：key：{}", key);
        }
        return result;
    }

    /**
     * 互斥锁，自动续期
     *
     * @param key
     */
    public boolean lock(String key) {
        RLock rLock = stringRedisson.getLock(key);
        if (rLock.isLocked()) {
            return false;
        }
        rLock.lock();
        return true;
    }

    /**
     * 手动释放锁
     *
     * @param key
     */
    public void unlock(String key) {
        RLock rLock = stringRedisson.getLock(key);
        if (rLock.isLocked()) {
            rLock.unlock();
        }
    }
}
